# -*- coding: utf-8 -*-

# -------------------------------
# Author    : linlingwei
# Email     : 951035650@qq.com
# File Name : commonCmds.py
# Date      : 2019/7/29 
# IDE       : PyCharm
# Version   : 1.0.1
# -------------------------------
import os
import time
import sys
import math


import maya.cmds as mc
import maya.mel as mel
import pymel.core as pm
import maya.OpenMaya as om

# import scripts.curveCmds as crvCore

def lAttr(obj, attr):
    return "{}.{}".format(obj, attr)

def attributeToDefault(obj,attr):
    atrName = "%s.%s" % (obj, attr)
    if mc.getAttr(atrName, settable=True):
        v = mc.attributeQuery(attr, listDefault=True, n=obj)[0]
        val = mc.getAttr(atrName)
        if v != val:
            # print(atrName)
            mc.setAttr(atrName, v)
    return

def channelAttrToDefault(obj):
    attrList = mc.listAttr(obj, k=True, w=True, unlocked=True, s=True)
    if not attrList:
        return
    for attr in attrList:
        attributeToDefault(obj, attr)

    return


def emptyGroup(obj, emptyStrs=["Zero","Con","Sdk"]):
    """
    version : 1.3.1
    support obj scale is not 1.
    
    version : 1.4.1
    Code and logic are more concise.
    """
    
    hi = mc.listRelatives(obj, p=True)
    nameList = list()
    
    pat = obj
    for empty in emptyStrs:
        grp = mc.group(em=True,name='_'.join([obj, empty]),parent=pat)
        pat = grp
        nameList.append(grp)
    
    if hi:
        mc.parent(nameList[0],hi[0])
    else:
        mc.parent(nameList[0],w=True)
    mc.parent(obj,grp)

    return nameList


def findRelateOrigShape(inobj):
    allList = mc.ls(mc.listRelatives(inobj, shapes=True, c=True), type="mesh")
    itsShapes = mc.listRelatives(inobj, shapes=1, pa=1)
    for sp in itsShapes:
        if sp not in allList:
            allList.append(sp)
    for obj in allList:
        value = mc.getAttr('%s.intermediateObject' % obj)
        upTrans = mc.listRelatives(obj, parent=True, pa=True)[0]
        hasOutPut = mc.listConnections("%s.worldMesh" % obj, d=1)
        hasInPut = mc.listConnections("%s.inMesh" % obj, s=1, d=0)
        if value \
                and upTrans == inobj \
                and hasOutPut is not None \
                and hasInPut is None:
            return obj


def findRelatedShape(inobj):
    controlShape, controlShapeWithPath, hiddenShape, hiddenShapeWithPath = "", "", "", ""
    cpTest = mc.ls(inobj, type="shape")
    if len(cpTest):
        return inobj
    else:
        rels = mc.listRelatives(inobj)
        
        if rels is None:
            return
        for r in rels:
            cpTest = mc.ls(inobj + "|" + r, type="shape")
            if 0 == len(cpTest):
                continue
            io = mc.getAttr(inobj + "|" + r + ".io")
            if io:
                continue
            visible = mc.getAttr(inobj + "|" + r + ".v")
            if 0 == visible:
                hiddenShape = r
                hiddenShapeWithPath = (inobj + "|" + r)
                continue
            controlShape = r
            controlShapeWithPath = (inobj + "|" + r)
            break
    for shape in [controlShape, controlShapeWithPath, hiddenShape, hiddenShapeWithPath]:
        if 0 != len(shape) and len(mc.ls(shape)) == 1:
            return shape
    return

def lockHideAttr(obj, attrList=None, lock=True, hide=True , ignore = None):
    if attrList is None:
        attrList = ['tx', 'ty', 'tz', 'rx', 'ry', 'rz', 'sx', 'sy', 'sz', 'v']
    if ignore is not None:
        for ig in ignore:
            attrList.remove(ig)
    for attr in attrList:
        if lock == 1:
            mc.setAttr(obj + '.' + attr, l=True, )
        if hide == 1:
            mc.setAttr(obj + '.' + attr, k=False, cb=False)
    return

def changColor(obj,colorId=0):
    mc.setAttr(obj+".overrideEnabled",1)
    mc.setAttr(obj+".overrideColor",colorId)
    shape = findRelatedShape(obj)
    if shape:
        mc.setAttr(shape + ".overrideEnabled", 1)
        mc.setAttr(shape + ".overrideColor", colorId)
    return

def hideShape(*args):
    # print(args)
    for obj in list(args):
        shape = findRelatedShape(obj)
        # print(shape)
        mc.setAttr(shape+'.v', 0)
    return

def lname(*args, **kwargs):
    args = [str(_) for _ in args if _]
    names = "_".join(args)
    
    return names

def transferAttr(sobj, tobj, attr=()):
    for at in attr:
        if mc.attributeQuery(at, node=sobj, ex=True):
            typ = mc.attributeQuery(at, node=sobj, at=True)
            
            k = mc.attributeQuery(at, node=sobj, k=True)
            dv = mc.addAttr("{}.{}".format(sobj, at), q=True, dv=True)
            if typ == 'enum':
                le = mc.attributeQuery(at, node=sobj, le=True)
                mc.addAttr(tobj, ln=at, at=typ, en=le[0], k=k, dv=dv)
                mc.connectAttr("{}.{}".format(tobj, at), "{}.{}".format(sobj, at))
                return
            if not mc.attributeQuery(at,node=tobj,ex=True):
                mc.addAttr(tobj, ln=at, at=typ, k=k, dv=dv)
            if mc.attributeQuery(at, node=sobj, mxe=True):
                mav = mc.attributeQuery(at, node=sobj, max=True)[0]
                mc.addAttr("{}.{}".format(tobj, at), e=True, max=mav)
            if mc.attributeQuery(at, node=sobj, mne=True):
                miv = mc.attributeQuery(at, node=sobj, min=True)[0]
                mc.addAttr("{}.{}".format(tobj, at), e=True, min=miv)
            
            mc.connectAttr("{}.{}".format(tobj, at), "{}.{}".format(sobj, at))
        else: print lAttr(sobj,at)+" not exist"
    
    return

def getWireBaseCrv(wire):
    baseCrv = mc.listConnections(wire + ".bw[0]", s=True, d=False)[0]
    
    return baseCrv

def hideJoint(*args):
    for arg in args:
        if mc.nodeType(arg) == "joint":
            mc.setAttr(arg+".drawStyle",2)
    return
def getObjInCrvParameter(crv,obj):
    crvShape = findRelatedShape(crv)
    # print(crvShape)

    csNode = pm.PyNode(crvShape)
    pt = mc.xform(obj,q=True,ws=True,t=True)
    incrvPt = csNode.closestPoint(pt)
    par = csNode.getParamAtPoint(incrvPt)

    return par

def getObjInCrvPoint(crv,obj):
    crvShape = findRelatedShape(crv)
    # print(crvShape)

    csNode = pm.PyNode(crvShape)
    pt = mc.xform(obj,q=True,ws=True,t=True)
    incrvPt = csNode.closestPoint(pt,)

    return incrvPt

def getObjInCrvDistance(crv,obj):
    crvShape = findRelatedShape(crv)
    # print(crvShape)

    csNode = pm.PyNode(crvShape)
    pt = mc.xform(obj,q=True,ws=True,t=True)
    dis = csNode.distanceToPoint(pt,"world")
    # par = csNode.getParamAtPoint(incrvPt)

    return dis
def selfFuncName():
    return sys._getframe(1).f_code.co_name

def noprefix_import(filePath):
    # file -import -type "mayaAscii"  -ignoreVersion -mergeNamespacesOnClash false -rpr "eyeTemplate" -options "v=0;"  -pr  -importFrameRate true  -importTimeRange "override" "F:/linlingwei/maya/code/mayaPy/rig/facial/templateFile/eyeTemplate.ma";
    mc.file(filePath,i=True,type="mayaAscii",ignoreVersion=True,mergeNamespacesOnClash=False,
            rpr = "eyeTemplate",options = "v=0;",pr=True,importFrameRate=True,importTimeRange= "override")
    return
def getNamespace():
    nslist = mc.namespaceInfo(lon=True, r=True)
    pass_ns = ["UI", "shared"]
    for ns in pass_ns:
        nslist.remove(ns)
    return nslist
def clearNamespace(progressBar=None):
    count = 0
    nslist = getNamespace()
    if not nslist:
        return
    if progressBar:
        progressBar.setMaxValue(len(nslist))
    while True:
        if count > 1000: break
        nslist = mc.namespaceInfo(lon=True)
        pass_ns = ["UI", "shared"]
        for ns in pass_ns: nslist.remove(ns)
        if not nslist: break
        for ns in nslist:
            if progressBar:
                progressBar.setStatus(ns)
                progressBar.setValue(count + 1)
            mc.namespace(rm=ns,mergeNamespaceWithRoot=True)
        count += 1
        
        if progressBar:
            progressBar.endProgress()
    return

def deleteUnusedNode():
    mel.eval("MLdeleteUnused();")
    return
def deleteUnusedDeformers():
    mel.eval("deleteUnusedDeformers();")
    return
def deleteUnusedSkinInfs():
    mel.eval("removeAllUnusedSkinInfs();")
    return
def deleteUnusedSets():
    mel.eval("deleteUnusedSets();")
    return
def deleteUnusedDisplayLayers():
    mel.eval('deleteEmptyLayers("Display");')
    return
def deleteUnusedRenderLayers():
    mel.eval('deleteEmptyLayers("Render");')
    return
def deleteUnusedGroupId():
    mel.eval('deleteUnusedCommon("groupId", 0,(uiRes("m_cleanUpScene.kDeletingUnusedGroupIDNodes"))) ')
    return


def fix_shapeName():
    mesh = mc.ls(typ = "mesh",fl=True)
    fix_list = list()
    if mesh:
        for m in mesh:
            transform = mc.listRelatives(m,p=True)[0]
            shapeName = transform+"Shape"
            if m != shapeName:
                mc.rename(m,shapeName)
                fix_list.append("%s >>> %s"%(m,shapeName))
    if fix_list:
        print fix_list
    return

def check_duplicate_name():
    all_transform = mc.ls(tr=True)
    translist = []
    for trans in all_transform:
        if "|" in trans:
            translist.append(trans)
    print translist
    return translist

def fix_duplicate_name():
    
    dn = check_duplicate_name()
    if dn:
        mc.select(dn)
        return 1
    else:
        return 0

def type_visibility(types):
    clu = mc.ls(type=types, fl=True)
    mc.hide(clu)
    return

def setDriverKeyframe(driver,driver_attr,driver_valuer,
                 driven,driven_attr,driven_valuen,
                 ott="linear", itt="linear"):
    mc.setDrivenKeyframe(driven + "."+driven_attr,v=driven_valuen,
                         cd=driver + "." + driver_attr, dv=driver_valuer,
                         ott=ott, itt=itt)
    return


def copyCurve(crv, name, space="object"):
    tCrvSp = pm.PyNode(findRelatedShape(crv))
    tCrvCvs = tCrvSp.getCVs(space=space)
    cvlist = []
    for i, point in enumerate(tCrvCvs):
        cvlist.append([point.x, point.y, point.z])
    
    tCrvKnt = tCrvSp.getKnots()
    tCrvDeg = tCrvSp.degree()
    
    nCrvObj = pm.curve(p=cvlist, k=tCrvKnt, d=tCrvDeg)
    
    nCrvObj.rename(name)
    return name

def mirrorCurve(crv,name):
    
    tmp = copyCurve(crv,name)
    org = mc.createNode("transform",)
    mc.parent(tmp,org)
    mc.setAttr(org+".sx",-1)
    #			makeIdentity -apply true -t 0 -r 0 -s 1 -n 0;
    mc.makeIdentity(org,apply=True,s=True,n=0)
    mc.parent(tmp,w=True)
    mc.delete(org)

    return tmp


def objToType(obj, name, mode=0, typ="transform"):
    trans = mc.createNode(typ, name=name,ss=True)
    
    if mode == 0:
        mc.delete(mc.pointConstraint(obj, trans, mo=False))
    if mode == 1:
        mc.parent(trans, obj)
        channelAttrToDefault(trans)
        mc.parent(trans, w=True)
    if mode == 2:
        mc.delete(mc.parentConstraint(obj, trans, mo=False))
    return trans

def localMirror(obj,space="object"):
    parent = mc.listRelatives(obj,p=1)
    tmp = mc.createNode("transform")
    if space == "object":
        mc.delete(mc.parentConstraint(obj,tmp,mo=False))
    elif space == "world":
        pass
    mc.parent(obj,tmp)
    mc.setAttr(tmp+".sx",-1)
    if parent :
        mc.parent(obj,parent,)
    else:
        mc.parent(obj,w=True)
    mc.delete(tmp)
    return

def jointOrient(jotlist):
    #joint -e  -oj xyz -secondaryAxisOrient yup -ch -zso;
    mc.joint(jotlist,e=True,oj ="xyz",secondaryAxisOrient="yup",ch=True,zso=True)

    return

def hideDeformer():
    mel.eval("hideShow -deformers -hide;")
    return

def createAnn(starObj, endObj, temp=True):
    p = mc.xform(starObj,q=True,ws=True,t=True)
    annShape = mc.annotate(endObj, p=p)
    ann = mc.listRelatives(annShape,p=True)[0]
    mc.parent(ann,starObj)
    
    if temp == 1:
        mc.setAttr(ann + ".overrideEnabled", 1)
        mc.setAttr(ann + '.overrideDisplayType', 2)
    
    return

def addStringAttr(obj, attrName, strs):
    mc.addAttr(obj, ln=attrName, dt="string", s=True)
    mc.setAttr("{}.{}".format(obj, attrName), strs, type="string")
    return

def setNotes(obj,strs):
    mc.addAttr(obj, ln="notes", dt="string", )
    mc.setAttr(obj+".notes", strs, type="string")

    return


def objToLocator(obj, name, parent=None, hide=True, suffix="loc"):
    loc = mc.spaceLocator(name=lname(name, suffix))[0]
    # mc.delete(mc.pointConstraint(obj, loc, mo=False))
    # mc.delete(mc.orientConstraint(obj, loc, mo=False))
    # mc.delete(mc.scaleConstraint(obj, loc, mo=False))
    mc.parent(loc, obj)
    channelAttrToDefault(loc)
    mc.parent(loc, w=True)
    if hide == 1:
        mc.hide(loc)
    if parent is not None and parent is not False:
        
        mc.parent(loc, parent)
    elif parent is False:
        pass
    else:
        mc.parent(loc, obj)
    return loc

def point_distance(p1,p2):
    xyz1 = mc.xform(p1,q=True,ws=True,t=True)
    xyz2 = mc.xform(p2,q=True,ws=True,t=True)
    
    dis = pow(sum([pow((a - b), 2) for a,b in zip(xyz1,xyz2) ]),.5)
    return dis


def insertNeg(obj, attr):
    
    pobj = pm.PyNode(obj).attr(attr).listConnections()[0]
    if pobj.type() == 'unitConversion':
        pobj = pm.PyNode(pobj).listConnections(p=True)[0]
    else:
        pobj = pm.PyNode(obj).attr(attr).listConnections(p=True)[0]
    
    negMd = mc.createNode("multiplyDivide", name=lname(obj, 'Neg_Md', ))
    pm.connectAttr(pobj,negMd+".input1X",f=1)
    # pobj.connect(pm.PyNode(negMd).attr("input1X"))
    mc.setAttr(negMd + ".input2X", -1)
    pm.PyNode(obj).disconnectAttr(attr)
    pm.PyNode(negMd).attr("outputX").connect(pm.PyNode(obj).attr(attr))
    
    return negMd

def searchReplaceNames(searchString,replaceString,onString):
    
    all_obj = []
    if onString == "all":
        all_obj = mc.ls()
    elif onString == "selected":
        all_obj = mc.ls(sl=True)
    elif onString == "hierarchy":
        all_obj = mc.ls(sl=True,dag=True)
    
    [_.replace(searchString,replaceString) for _ in all_obj]
    
    return
def angle(v1, v2):
    v1x,v1y,v1z = v1
    v2x, v2y, v2z = v2
    
    angle_value = (v1x*v2x + v1y*v2y + v1z*v2z)/\
                  (math.sqrt(v1x*v1x + v1y*v1y + v1z*v1z)*math.sqrt(v2x*v2x + v2y*v2y + v2z*v2z))
    
    # dx1 = v1[2] - v1[0]
    # dy1 = v1[3] - v1[1]
    # dx2 = v2[2] - v2[0]
    # dy2 = v2[3] - v2[1]
    # angle1 = math.atan2(dy1, dx1)
    # angle1 = int(angle1 * 180/math.pi)
    # # print(angle1)
    # angle2 = math.atan2(dy2, dx2)
    # angle2 = int(angle2 * 180/math.pi)
    # # print(angle2)
    # if angle1*angle2 >= 0:
    #     included_angle = abs(angle1-angle2)
    # else:
    #     included_angle = abs(angle1) + abs(angle2)
    #     if included_angle > 180:
    #         included_angle = 360 - included_angle
    return math.degrees(math.acos(angle_value))

if __name__ == '__main__':
    pass